//
//  BSXMLPaser.m
//  Spriter_forCocs2d
//
//  Created by Yang Bean on 13/4/15.
//
//
#import "BSBoneRef.h"
#import "BSXMLPaser.h"
#import "BSTimeLine.h"
#import "BSAnimation.h"
#import "BSMainLine.h"
#import "BSObject.h"
#import "BSObjectRef.h"
#import "BSKeyRef.h"
#import "BSBone.h"
#import "tinyxml.h"
#import "BSFolder.h"
#import "BSFile.h"
#import "BSSpriterData.h"
@interface BSXMLPaser()
+ (BSAnimation*)animationWithAnimationNode:(TiXmlNode*)animationNode;

+ (BSFolder*)folderWithXMLNode:(TiXmlNode*)node;

+ (BSMainLine*)mainlineWithXmlNode:(TiXmlNode*)lineNode;
+ (BSObjectRef*)objRefWithXmlElement:(TiXmlElement*)objRefElement;
+ (BSBoneRef*)boneRefWithXmlElement:(TiXmlElement*)boneRefElement;

+ (BSTimeLine*)timelineWithXmlNode:(TiXmlNode*)lineNode;
+ (BSObject*)objectWithXmlElement:(TiXmlElement*)objElement
                            keyId:(int)keyID
                             spin:(int)spin
                             time:(int)time;
+ (BSBone*)boneWithXmlElement:(TiXmlElement*)objElement
                        keyid:(int)keyID
                         spin:(int)spin
                         time:(int)time;

+ (int)intValueFromXmlElement:(TiXmlElement*)element keyName:(const char*)keyName;
+ (float)floatValueFromXmlElement:(TiXmlElement*)element keyName:(const char*)keyName;
+ (BOOL)boolValueFromXmlElement:(TiXmlElement*)element keyName:(const char*)keyName;
+ (float)floatValueFromXmlElement:(TiXmlElement*)element keyName:(const char*)keyName defNumber:(float)defNumber;
NSString* NSStringWIthUTF8String(const char* s);

@end
@implementation BSXMLPaser
- (id)initWithFileName:(NSString*)fn
{
    self = [super init];
    if (self) {
        
    }
    return self;
}
+ (BSSpriterData*)spriteDataWithFile:(NSString*)fn
{
    NSString *filePath = [[NSBundle mainBundle] pathForResource:fn
                                                         ofType:@"scml"];
    NSData *data = [[NSData alloc] initWithContentsOfFile:filePath];
    char *buffer = (char *)[data bytes];
    if (buffer == NULL)
    {
        [data release];
        return false;
    }
    TiXmlDocument doc;
    
    doc.Parse(buffer);
    
    BSSpriterData* spriteData = [[BSSpriterData alloc] init];
    spriteData.folders = [[[NSMutableDictionary alloc] init] autorelease];
    spriteData.animations = [[[NSMutableDictionary alloc] init] autorelease];
    
    TiXmlNode *root = doc.FirstChild("spriter_data");
    if (root)
    {
        
        TiXmlElement *element = root->ToElement();
        
        const char *version = element->Attribute("scml_version");
        NSLog(@"version = %s", version);
        const char *generator = element->Attribute("generator");
        NSLog(@"generator = %s", generator);
        const char *generatorVersion = element->Attribute("generator_version");
        NSLog(@"generatorVersion = %s", generatorVersion);
        
        for (TiXmlNode* entityNode = root->FirstChild(); entityNode; entityNode = entityNode->NextSibling())
        {
            element = entityNode->ToElement();
            
            NSString* key_id = NSStringWIthUTF8String(element->Attribute("id"));
            NSLog(@"key_id = %@", key_id);
            if (element)
            {
                const char *tab = element->Value();
                if (strcmp(tab, "folder")==0)
                {
                    BSFolder* f = [BSXMLPaser folderWithXMLNode:entityNode];
                    [spriteData.folders setObject:f forKey:key_id];
                    NSLog(@"folder = %@", f);
                }
                else if (strcmp(tab, "entity")==0)
                {
                    NSString* name = [NSString stringWithUTF8String:element->Attribute("name")];
                    NSLog(@"entity name = %@", name);
                    for (TiXmlNode* animationNode = entityNode->FirstChild(); animationNode; animationNode = animationNode->NextSibling())
                    {
                        key_id = NSStringWIthUTF8String(animationNode->ToElement()->Attribute("id"));
                        BSAnimation* anim = [BSXMLPaser animationWithAnimationNode:animationNode];
                        [spriteData.animations setObject:anim
                                                  forKey:key_id];
                    }
                }
            }
        }
    }
    [data release];
    return [spriteData autorelease];
}
+ (BSFolder*)folderWithXMLNode:(TiXmlNode*)node
{
    TiXmlElement* element = node->ToElement();
    NSString* name = NSStringWIthUTF8String(element->Attribute("name"));
    int fid = [BSXMLPaser intValueFromXmlElement:element keyName:"id"];
    BSFolder* folder = [[BSFolder alloc] initWithFolderId:fid name:name];
    folder.files = [[[NSMutableDictionary alloc] init] autorelease];
    for (TiXmlNode* fileNode = node->FirstChild();
         fileNode; fileNode = fileNode->NextSibling())
    {
        TiXmlElement* fileElement = fileNode->ToElement();
        int fileId = [BSXMLPaser intValueFromXmlElement:fileElement keyName:"id"];
        NSString* name = NSStringWIthUTF8String(fileElement->Attribute("name"));
        int width = [BSXMLPaser intValueFromXmlElement:fileElement keyName:"width"];
        int height = [BSXMLPaser intValueFromXmlElement:fileElement keyName:"height"];
        
        BSFile* file = [[BSFile alloc] initWithFileID:fileId
                                                 name:name
                                                width:width
                                               height:height];
        [folder.files setObject:[file autorelease]
                         forKey:NSStringWIthUTF8String(fileElement->Attribute("id"))];
    }
    return [folder autorelease];
}
+ (BSAnimation*)animationWithAnimationNode:(TiXmlNode*)animationNode
{
    
    TiXmlElement* element = animationNode->ToElement();
    int animID = [BSXMLPaser intValueFromXmlElement:element keyName:"id"];
    NSString* name = NSStringWIthUTF8String(element->Attribute("name"));
    int length = [BSXMLPaser intValueFromXmlElement:element keyName:"length"];
    int looping = [BSXMLPaser boolValueFromXmlElement:element keyName:"looping"];
    BSAnimation* animation = [[BSAnimation alloc] initWithId:animID
                                                        name:name
                                                      length:length
                                                      isLoop:looping];
    for (TiXmlNode* lineNode = animationNode->FirstChild();
         lineNode;
         lineNode = lineNode->NextSibling())
    {
        const char *tab = lineNode->Value();
        if (strcmp(tab, "mainline")==0)
        {
            BSMainLine* mainline = [BSXMLPaser mainlineWithXmlNode:lineNode];
            [animation setMainline:mainline];
        }
        else if(strcmp(tab, "timeline")==0)
        {
            TiXmlElement* lineElement = lineNode->ToElement();
            int Id = [BSXMLPaser intValueFromXmlElement:lineElement keyName:"id"];
            [animation addTimeLine:[BSXMLPaser timelineWithXmlNode:lineNode]
                               key:[NSString stringWithFormat:@"%d",Id]];
        }
        else
        {
            NSLog(@"error unknow line type");
        }
    }
    
    return [animation autorelease];
}
+ (BSTimeLine*)timelineWithXmlNode:(TiXmlNode*)lineNode
{
    int tid = [self intValueFromXmlElement:lineNode->ToElement()
                                   keyName:"id"];
    BSTimeLine* timeline = [[BSTimeLine alloc] init];
    [timeline setTimeLineId:tid];
    for (TiXmlNode* keyNode = lineNode->FirstChild();
         keyNode; keyNode = keyNode->NextSibling())
    {
        TiXmlElement* keyElement = keyNode->ToElement();
        int keyId = [BSXMLPaser intValueFromXmlElement:keyElement keyName:"id"];
        int spin = [BSXMLPaser intValueFromXmlElement:keyElement keyName:"spin"];
        int time = [BSXMLPaser intValueFromXmlElement:keyElement keyName:"time"];
        for (TiXmlNode* objNode = keyNode->FirstChild();
             objNode; objNode = objNode->NextSibling())
        {
            const char *tab = objNode->Value();
            TiXmlElement* objElement =  objNode->ToElement();
            if (strcmp(tab, "object")==0)
            {
                BSObject* obj = [BSXMLPaser objectWithXmlElement:objElement
                                                           keyId:keyId
                                                            spin:spin
                                                            time:time];
                [timeline addObject:obj
                              inKey:[NSString stringWithFormat:@"%d",keyId]];
            }
            else if (strcmp(tab, "bone")==0)
            {
                BSBone* bone = [BSXMLPaser boneWithXmlElement:objElement
                                                        keyid:keyId
                                                         spin:spin
                                                         time:time];
                [timeline addBone:bone inKey:[NSString stringWithFormat:@"%d",keyId]];
            }
            else
            {
                NSLog(@"error in load xml key value");
            }
        }
    }
    return [timeline autorelease];
}
+ (BSBone*)boneWithXmlElement:(TiXmlElement*)objElement
                        keyid:(int)keyID
                         spin:(int)spin
                         time:(int)time
{
    CGPoint point = CGPointMake([BSXMLPaser floatValueFromXmlElement:objElement keyName:"x"],
                                [BSXMLPaser floatValueFromXmlElement:objElement keyName:"y"]);
    CGPoint scale = CGPointMake([BSXMLPaser floatValueFromXmlElement:objElement keyName:"scale_x" defNumber:1.0f],
                                [BSXMLPaser floatValueFromXmlElement:objElement keyName:"scale_y" defNumber:1.0f]);
    float angle = [BSXMLPaser floatValueFromXmlElement:objElement keyName:"angle"];
    BSBone* bone = [[BSBone alloc] initWithPoint:point
                                           scale:scale
                                           angle:angle
                                            spin:spin
                                           keyID:keyID time:time];
    return [bone autorelease];
}
+ (BSObject*)objectWithXmlElement:(TiXmlElement*)objElement
                            keyId:(int)keyID
                             spin:(int)spin
                             time:(int)time
{
    int folder = [BSXMLPaser intValueFromXmlElement:objElement
                                      keyName:"folder"];
    int file = [BSXMLPaser intValueFromXmlElement:objElement
                                    keyName:"file"];
    CGPoint point = CGPointMake([BSXMLPaser floatValueFromXmlElement:objElement keyName:"x"],
                                [BSXMLPaser floatValueFromXmlElement:objElement keyName:"y"]);
    CGPoint pivot = CGPointMake([BSXMLPaser floatValueFromXmlElement:objElement keyName:"pivot_x"],
                                [BSXMLPaser floatValueFromXmlElement:objElement keyName:"pivot_y"]);
    float scalex = [BSXMLPaser floatValueFromXmlElement:objElement keyName:"scale_x" defNumber:1.0f];

    float scaley = [BSXMLPaser floatValueFromXmlElement:objElement keyName:"scale_y" defNumber:1.0f];
//    int time = [BSXMLPaser intValueFromXmlElement: keyName:"time"];
    CGPoint scale = CGPointMake(scalex, scaley);
    
    float angle = [BSXMLPaser floatValueFromXmlElement:objElement keyName:"angle"];
    float alpha = [BSXMLPaser floatValueFromXmlElement:objElement keyName:"a" defNumber:1.0f];
    BSObject* obj = [[BSObject alloc] initWithImagfilder:folder
                                                    file:file
                                                   point:point
                                                   angle:angle
                                                   pivot:pivot
                                                   scale:scale
                                                    spin:spin
                                                     key:keyID
                                                    time:time
                                                       a:alpha];
    return [obj autorelease];
}

+ (BSMainLine*)mainlineWithXmlNode:(TiXmlNode*)lineNode
{
    BSMainLine* mainline = [[BSMainLine alloc] init];
    NSMutableDictionary* keyDict = [NSMutableDictionary dictionary];
    [mainline setKeyRefs:keyDict];
    for (TiXmlNode* keyNode = lineNode->FirstChild();
         keyNode; keyNode = keyNode->NextSibling())
    {
        TiXmlElement* keyElement = keyNode->ToElement();
        int time = [BSXMLPaser intValueFromXmlElement:keyElement
                                        keyName:"time"];
        int keyId = [BSXMLPaser intValueFromXmlElement:keyElement
                                         keyName:"id"];
        
        BSKeyRef* keyRef = [[[BSKeyRef alloc] initWithKeyId:keyId
                                                      time:time] autorelease];
        [keyDict setObject:keyRef forKey:[NSString stringWithFormat:@"%d",keyId]];
        
        NSMutableArray* objRefArray = [[NSMutableArray alloc] init];
        NSMutableArray* boneRefArray = [[NSMutableArray alloc] init];
        [keyRef setBonRefeArray:[boneRefArray autorelease]];
        [keyRef setObjRefArray:[objRefArray autorelease]];
        for (TiXmlNode* refNode = keyNode->FirstChild();
             refNode;
             refNode = refNode->NextSibling())
        {
            const char *tab = refNode->Value();
            if (strcmp(tab, "object_ref")==0)
            {
                TiXmlElement* objRefElement = refNode->ToElement();
                [objRefArray addObject:[BSXMLPaser objRefWithXmlElement:objRefElement]];
            }
            else if (strcmp(tab, "bone_ref")==0)
            {
                TiXmlElement* objRefElement = refNode->ToElement();
                [boneRefArray addObject:[BSXMLPaser boneRefWithXmlElement:objRefElement]];
            }
            else
            {
                NSLog(@"error in load xml key value");
            }
        }
    }
    
    return [mainline autorelease];
}

+ (BSObjectRef*)objRefWithXmlElement:(TiXmlElement*)objRefElement
{
    int objrefID = [BSXMLPaser intValueFromXmlElement:objRefElement keyName:"id"];
    int timeline = [BSXMLPaser intValueFromXmlElement:objRefElement keyName:"timeline"];
    int key = [BSXMLPaser intValueFromXmlElement:objRefElement keyName:"key"];
    int z = [BSXMLPaser intValueFromXmlElement:objRefElement keyName:"z_index"];
    
    BSObjectRef* objRef = [[BSObjectRef alloc] initWithId:objrefID
                                                 timeLine:timeline
                                                      key:key
                                                        z:z];
    return [objRef autorelease];
}
+ (BSBoneRef*)boneRefWithXmlElement:(TiXmlElement*)boneRefElement
{
    int refID = [BSXMLPaser intValueFromXmlElement:boneRefElement keyName:"id"];
    int timeline = [BSXMLPaser intValueFromXmlElement:boneRefElement keyName:"timeline"];
    int key = [BSXMLPaser intValueFromXmlElement:boneRefElement keyName:"key"];
    int parent = [BSXMLPaser intValueFromXmlElement:boneRefElement keyName:"parent"];
    
    BSBoneRef* boneRef = [[BSBoneRef alloc] initWithBoneId:refID
                                                timelineID:timeline
                                                     keyID:key
                                              parentBoneID:parent];
    return [boneRef autorelease];
}
+ (int)intValueFromXmlElement:(TiXmlElement*)element keyName:(const char*)keyName
{
    int intValue = 0;
    if (!element)
    {
        NSLog(@"error in get null element in intValueFromXmlElement");
        return 0;
    }
    
    if ((element->QueryIntAttribute(keyName, &intValue) == TIXML_SUCCESS))
        return intValue;
    return 0;
}
+ (float)floatValueFromXmlElement:(TiXmlElement*)element keyName:(const char*)keyName defNumber:(float)defNumber
{
    float floatValue = defNumber;
    if (!element)
    {
        NSLog(@"error in get null element in floatValueFromXmlElement");
        return defNumber;
    }
    if (element->QueryFloatAttribute(keyName, &floatValue) == TIXML_SUCCESS)
        return floatValue;
    else
        floatValue = defNumber;
    return defNumber;
}
+ (float)floatValueFromXmlElement:(TiXmlElement*)element keyName:(const char*)keyName
{
    float floatValue = 0;
    if (!element)
    {
        NSLog(@"error in get null element in floatValueFromXmlElement");
        return 0;
    }
    if (element->QueryFloatAttribute(keyName, &floatValue) == TIXML_SUCCESS)
        return floatValue;
    else
        floatValue = 0;
    return 0;
}
+ (BOOL)boolValueFromXmlElement:(TiXmlElement*)element keyName:(const char*)keyName
{
    if (!element)
    {
        NSLog(@"error in get null element in floatValueFromXmlElement");
        return NO;
    }
    const char* boolChar = element->Attribute(keyName);
    
    if (strcmp(boolChar, "true")) return YES;
    else if (strcmp(boolChar, "false")) return NO;
    else NSLog(@"error this is not bool value");
    return NO;
}
NSString* NSStringWIthUTF8String(const char* s)
{
    if (s == nil) {
        NSLog(@"error string is null");
        return @" ";
    }
    else
        return [NSString stringWithUTF8String:s];
}
@end
